package com.jason.www.code.impl;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.jason.www.code.IPayClient;
import com.jason.www.code.ScanPayReqData;
import com.jason.www.code.XMLUtil;
import com.jason.www.commons.PropertyConfigurer;
import com.jason.www.commons.http.IHttpClient;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

import static org.apache.commons.lang3.StringUtils.isEmpty;
import static org.apache.commons.lang3.StringUtils.isNotEmpty;

/**
 * 微信支付开发API https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_1
 */
@Slf4j
@Component("wxpayClient")
public class WXpayClient implements IPayClient {


    @Autowired
    private @Qualifier("httpClientService")
    IHttpClient httpClient;

    @Autowired
    private PropertyConfigurer propertyConfigurer;

    public static final String signType = "MD5";

    public static final String PAY_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";

    public static final String INPUT_CHAR_SET = "UTF-8";

    @Override
    public String buildRequestUrl(Map<String, String> params) {
        String result = null;
        try {
            String subject = params.get("subject");
            String orderId = params.get("orderId");
            BigDecimal totalMoney = new BigDecimal(params.get("totalPrice"));
            String url = params.get("requestUrl");
            String ipAddr = params.get("ipAddr");
            String tradeType = "JSAPI";
            if (propertyConfigurer.getOverhttps().equalsIgnoreCase("Y")
                    && url.startsWith("http://")) {
                url = url.replace("http://", "https://");
            }
            String notifyUrl = url + propertyConfigurer.getWXpayNotifyUrl();
            if (isEmpty(subject)) {
                log.error("产品名称为空,设置产品名称为testprod");
                subject = "testprod";
            }
            long money = totalMoney.multiply(new BigDecimal(100)).longValue();
            ScanPayReqData payData = new ScanPayReqData("", subject, "", orderId, money, "WEB", ipAddr, "", "", "", notifyUrl, tradeType, propertyConfigurer.getWXpayOpenId(), propertyConfigurer.getWXpayAppId(), propertyConfigurer.getWXpayPartner());

            String timeout = params.get("timeout");
            if (isNotEmpty(timeout)) {
                payData.setTime_start(params.get("timestart"));
                payData.setTime_expire(params.get("timeexpire"));
            }
            Map<String, String> map = BeanUtils.describe(payData);
            map.remove("class");
            String sign = getSign(map, propertyConfigurer.getWXpayPrivateKey());
            payData.setSign(sign);
            log.info("微信支付提交参数::{}", JSON.toJSONString(payData));
            result = httpClient.postXml(WXpayClient.PAY_URL, payData, WXpayClient.INPUT_CHAR_SET);
            Map<String, String> resultMap = XMLUtil.getMapFromXML(result);
            log.info("微信支付返回结果 {} ", JSON.toJSONString(resultMap));
            if ("SUCCESS".equals(resultMap.get("result_code"))) {
                JSONObject json = new JSONObject();
                json.put("timestamp", payData.getTimeStamp());
                json.put("nonceStr", payData.getNonce_str());
                json.put("package", "prepay_id=" + resultMap.get("prepay_id"));
                json.put("signType", WXpayClient.signType);
                String paySignStr = new StringBuilder("appId=").append(propertyConfigurer.getWXpayAppId()).append("&nonceStr=").append(payData.getNonce_str()).append("&package=")
                        .append("prepay_id=").append(resultMap.get("prepay_id")).append("&signType=").append(WXpayClient.signType).append("&timeStamp=")
                        .append(payData.getTimeStamp()).append("&key=").append(propertyConfigurer.getWXpayPrivateKey()).toString();
                String paySign = DigestUtils.md5Hex(paySignStr.getBytes(WXpayClient.INPUT_CHAR_SET)).toUpperCase();
                json.put("paySign", paySign);
                return json.toJSONString();
            }else{
                JSONObject json = new JSONObject();
                json.put("err_code_des", resultMap.get("err_code_des"));
                return  json.toJSONString();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    @Override
    public Boolean verifyCallbackHmac(Map<String, String> params) {
        String signFromAPIResponse = params.get("sign");
        if (isEmpty(signFromAPIResponse)) {
            log.error("API返回的数据签名数据不存在，有可能被第三方篡改!!!");
            return false;
        }
        log.error("服务器回包里面的签名是:" + signFromAPIResponse);
        //清掉返回数据对象里面的Sign数据（不能把这个数据也加进去进行签名），然后用签名算法进行签名
        params.put("sign", "");
        //将API返回的数据根据用签名算法进行计算新的签名，用来跟API返回的签名进行比较
        String signForAPIResponse = getSign(params, propertyConfigurer.getWXpayPrivateKey());
        if (!signForAPIResponse.equals(signFromAPIResponse)) {
            //签名验不过，表示这个API返回的数据有可能已经被篡改了
            log.error("API返回的数据签名验证不通过，有可能被第三方篡改!!!");
            log.error("输入的验证内容是:" + createLinkString(params));
            return false;
        }
        log.error("恭喜，API返回的数据签名验证通过!!!");
        return true;
    }

    public static String getSign(Map<String, String> map, String privateKey) {
        String result = createLinkString(map);
        result += "&key=" + privateKey;
        log.error("originStr=" + result);
        try {
            String code = DigestUtils.md5Hex(result.getBytes(WXpayClient.INPUT_CHAR_SET)).toUpperCase();
            log.error("signmd5=" + code);
            return code;

        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return result;
    }


    private static String createLinkString(Map<String, String> params) {
        if (params == null || params.size() == 0){
            return "";
        }

        List<String> keys = new ArrayList<String>(params.keySet());
        //Collections.sort(keys, String.CASE_INSENSITIVE_ORDER);
        Collections.sort(keys, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.compareTo(o2);
            }
        });

        String prestr = "";
        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            String value = params.get(key);
            if (isNotEmpty(value)){
                if (i == keys.size() - 1) {// 拼接时，不包括最后一个&字符
                    prestr = prestr + key + "=" + value;
                } else {
                    prestr = prestr + key + "=" + value + "&";
                }
            }
        }
        return prestr;
    }
}
